﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Kugar.Core.BaseStruct;
using Kugar.Core.Collections;
using Kugar.Core.ExtMethod;

namespace Kugar.UI.WinForm.Button
{
    public partial class ImageButtonListView : UserControl
    {
        private ButtonItemCollection itemCollection = new ButtonItemCollection();
        private Size itemSize = new Size(64, 64);
        private Padding itemMargin = new Padding(3);
        private volatile ImageButtonListViewItem _selectedItem;
        private bool _isMouseDowning = false;
        private Point _oldLocation;
        private LabelEx _oldLabel = null;
        private int _oldScrollPos = 0;

        public ImageButtonListView()
        {
            InitializeComponent();

            flowLayoutPanel1.HorizontalScroll.Enabled = false;
            flowLayoutPanel1.HorizontalScroll.Visible = false;

            flowLayoutPanel1.VerticalScroll.Enabled = true;

            itemCollection.CollectionChanging += itemCollection_CollectionChanging;
            itemCollection.CollectionChanged += itemCollection_CollectionChanged;

            flowLayoutPanel1.ControlAdded += flowLayoutPanel1_ControlAdded;

            flowLayoutPanel1.MouseWheel += flowLayoutPanel1_MouseWheel;

        }



        public Padding ItemMargin
        {
            set
            {
                if (itemMargin != value)
                {
                    itemMargin = value;
                    this.Invalidate();
                }

            }
            get { return itemMargin; }
        }

        public Size ItemSize
        {
            get { return itemSize; }
            set
            {
                if (itemSize != value)
                {
                    foreach (Label lbl in flowLayoutPanel1.Controls)
                    {
                        if (lbl != null)
                        {
                            lbl.Size = value;
                        }
                    }
                }

                itemSize = value;
            }
        }

        public ButtonItemCollection Items
        {
            get { return itemCollection; }
        }

        public ImageButtonListViewItem GetItemFromPoint(Point point)
        {
            var lbl = flowLayoutPanel1.GetChildAtPoint(point);

            if (lbl != null)
            {
                foreach (var item in itemCollection)
                {
                    if (item.Key == lbl.Name)
                    {
                        return item;
                    }
                }
            }

            return null;

        }

        public override void Refresh()
        {
            flowLayoutPanel1.Controls.Clear();

            base.Refresh();

            refreshList();
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            //base.OnInvalidated(e);
        }

        public event EventHandler ItemSelectedChanged;

        public event EventHandler<ItemSelectedChangingEventArgs> ItemSelectedChanging;

        public event EventHandler<ItemMouseEventArgs> ItemMouseDoubleClick;

        public event EventHandler<ItemMouseEventArgs> ItemMouseDown;

        public event EventHandler<ItemMouseEventArgs> ItemMouseUp;




        private void itemCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs<ImageButtonListViewItem> e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if (e.NewStartingIndex != -1)
                {
                    //flowLayoutPanel1.Invalidate();
                }

                foreach (var listViewItem in e.NewItems)
                {
                    var lbl = buildLabel(listViewItem.Text, listViewItem.Key, listViewItem.Tag,
                                            listViewItem.BackImage, listViewItem);

                    listViewItem.Control = lbl;

                    if (e.NewStartingIndex == -1)
                    {
                        flowLayoutPanel1.Controls.Add(lbl);



                    }

                    lbl.MouseDown += flowLayoutPanel1_MouseDown;
                    lbl.MouseMove += flowLayoutPanel1_MouseMove;
                    lbl.MouseUp += flowLayoutPanel1_MouseUp;

                }

                if (e.NewStartingIndex != -1)
                {
                    refreshList();
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (var listViewItem in e.NewItems)
                {
                    //TODO:去除点击绑定

                    listViewItem.Control.MouseDown -= flowLayoutPanel1_MouseDown;
                    listViewItem.Control.MouseMove -= flowLayoutPanel1_MouseMove;
                    listViewItem.Control.MouseUp -= flowLayoutPanel1_MouseUp;

                    flowLayoutPanel1.Controls.Remove(listViewItem.Control);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Replace)
            {
                var item = flowLayoutPanel1.Controls.Find(e.OldItems[0].Key, false)[0];

                item.Text = e.NewItems[0].Text;
                item.Tag = e.NewItems[0].Tag;
                item.BackgroundImage = e.NewItems[0].BackImage;
            }
        }

        private void itemCollection_CollectionChanging(object sender, NotifyCollectionChangingEventArgs<ImageButtonListViewItem> e)
        {
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                foreach (Label lbl in flowLayoutPanel1.Controls)
                {
                    lbl.MouseDown -= flowLayoutPanel1_MouseDown;
                    lbl.MouseMove -= flowLayoutPanel1_MouseMove;
                    lbl.MouseUp -= flowLayoutPanel1_MouseUp;

                    //TODO:去除点击绑定
                }

                if (e.OldItems != null)
                {
                    foreach (var listViewItem in e.OldItems)
                    {
                        listViewItem.Control = null;
                    }
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (var listViewItem in e.NewItems)
                {
                    if (flowLayoutPanel1.Controls.Find(listViewItem.Key, false).Length > 0)
                    {
                        throw new Exception(string.Format("已存在Key为{0}的按钮", listViewItem.Key));
                    }
                }
            }
        }

        private LabelEx buildLabel(string text, string key, object tag, Image backImg, ImageButtonListViewItem data)
        {
            var t = new LabelEx();

            t.AutoSize = false;
            t.Size = this.itemSize;
            t.Name = key;
            t.Text = text;
            t.TextAlign = ContentAlignment.MiddleCenter;
            t.Tag = tag;
            t.Image = backImg;
            t.BorderStyle = BorderStyle.FixedSingle;
            t.BorderColor = Color.Black;

            t.Margin = new Padding(3);
            //t.BorderColor = Color.Red;
            t.Tag = data;

            //t.Refresh();

            return t;
        }

        private void refreshList()
        {
            flowLayoutPanel1.Controls.Clear();

            foreach (var listViewItem in itemCollection)
            {
                flowLayoutPanel1.Controls.Add(listViewItem.Control);
            }
        }

        private void flowLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
        {
            flowLayoutPanel1.Focus();
            ImageButtonListViewItem label = GetItemFromPoint(_oldLocation);
            if (e.Button == MouseButtons.Left)
            {
                var location = e.Location;

                if (!(sender is FlowLayoutPanel))
                {
                    location = flowLayoutPanel1.PointToClient(((Control)sender).PointToScreen(e.Location));
                }

                _isMouseDowning = true;
                _oldLocation = location;// flowLayoutPanel1.PointToClient(e.Location);
                _oldScrollPos = flowLayoutPanel1.VerticalScroll.Value;
                //label = GetItemFromPoint(_oldLocation);

                if (label != null)
                {
                    _oldLabel = label.Control;
                }
            }

            if (label != null)
            {
                OnItemMouseDown(e, label);
            }
            else
            {
                OnMouseDown(e);
            }


        }

        private void flowLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && _isMouseDowning)
            {
                var location = e.Location;

                if (!(sender is FlowLayoutPanel))
                {
                    location = flowLayoutPanel1.PointToClient(((Control)sender).PointToScreen(e.Location));
                }

                //var p = flowLayoutPanel1.PointToClient(e.Location);

                var offset = location.Y - _oldLocation.Y;
                //Debug.Write(e.Y);
                flowLayoutPanel1.VerticalScroll.Value = (_oldScrollPos - offset * 5).ToBetween(0, flowLayoutPanel1.VerticalScroll.Maximum);
            }

            OnMouseMove(e);
        }

        private void flowLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
        {
            var location = e.Location;

            if (!(sender is FlowLayoutPanel))
            {
                location = flowLayoutPanel1.PointToClient(((Control)sender).PointToScreen(e.Location));
            }

            var newLabel = GetItemFromPoint(location);

            if (e.Button == MouseButtons.Left && _isMouseDowning)
            {
                //var newPos = location;// flowLayoutPanel1.PointToClient(e.Location);


                if (_oldLabel != null && newLabel != null)
                {
                    //var newLabel = GetItemFromPoint(newPos);

                    if (newLabel.Control == _oldLabel)
                    {
                        OnItemSelected(newLabel);
                    }
                }
                else if (newLabel != null)
                {
                    if ((location.X >= _oldLocation.X - 5 && location.X <= _oldLocation.X + 5) && (location.Y >= _oldLocation.Y - 5 && location.Y <= _oldLocation.Y + 5))
                    {
                        OnItemSelected(newLabel);
                    }
                }

                _isMouseDowning = false;
            }

            if (newLabel != null)
            {
                OnItemMouseUp(e, newLabel);
            }
            else
            {
                OnMouseUp(e);
            }
            
        }

        private void flowLayoutPanel1_Leave(object sender, EventArgs e)
        {
            _isMouseDowning = false;

            OnMouseLeave(e);

            //Debug.Write("mouse leave");
            //flowLayoutPanel1.FindForm().Focus();
        }

        private void flowLayoutPanel1_ControlAdded(object sender, ControlEventArgs e)
        {
            var colCount = flowLayoutPanel1.ClientSize.Width / (itemSize.Width + itemMargin.Left + itemMargin.Right);

            var itemHeight = (itemSize.Height + itemMargin.Top + itemMargin.Bottom);

            var rowCount = (int)Math.Ceiling((double)itemCollection.Count / colCount);

            if (rowCount * itemHeight > flowLayoutPanel1.ClientSize.Height)
            {
                flowLayoutPanel1.VerticalScroll.Visible = true;
                flowLayoutPanel1.VerticalScroll.Enabled = true;

                flowLayoutPanel1.VerticalScroll.Maximum = rowCount * itemHeight;
            }
            else
            {
                flowLayoutPanel1.VerticalScroll.Visible = false;
                flowLayoutPanel1.VerticalScroll.Enabled = false;
            }
        }

        private void flowLayoutPanel1_MouseWheel(object sender, MouseEventArgs e)
        {
            var location = e.Location;

            if (sender != flowLayoutPanel1)
            {
                location = flowLayoutPanel1.PointToClient(((Control)sender).PointToScreen(e.Location));
            }

            if (location.X >= 0 && location.X <= flowLayoutPanel1.ClientRectangle.Right && location.Y >= 0 && location.Y <= flowLayoutPanel1.ClientRectangle.Bottom)
            {
                flowLayoutPanel1.VerticalScroll.Value = (flowLayoutPanel1.VerticalScroll.Value - e.Delta).ToBetween(0, flowLayoutPanel1.VerticalScroll.Maximum);
            }

            OnMouseWheel(e);
        }

        private void flowLayoutPanel1_MouseEnter(object sender, EventArgs e)
        {
            //flowLayoutPanel1.Focus();

            OnMouseEnter(e);
        }

        private void flowLayoutPanel1_MouseDoubleClick(object sender, MouseEventArgs e)
        {

            var location = e.Location;

            if (!(sender is FlowLayoutPanel))
            {
                location = flowLayoutPanel1.PointToClient(((Control)sender).PointToScreen(e.Location));
            }

            var item = GetItemFromPoint(location);

            if (item != null)
            {
                OnItemMouseDoubleClick(e,item);
            }
            else
            {
                OnMouseDoubleClick(e);
            }
        }

        public ImageButtonListViewItem SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    OnItemSelected(value);
                }
            }
        }

        public void SelectByKey(string key)
        {
            OnItemSelected(GetItemByKey(key));
        }

        public ImageButtonListViewItem GetItemByKey(string key)
        {
            var t = itemCollection.FindItem((i) => i.Key == key);

            if (t != null)
            {
                return t;
            }
            else
            {
                return null;
            }
        }

        private void OnItemSelected(ImageButtonListViewItem selectedItem)
        {
            if (ItemSelectedChanging != null)
            {
                var e = new ItemSelectedChangingEventArgs(selectedItem);

                ItemSelectedChanging(this, e);

                if (e.Cancel)
                {
                    return;
                }
            }

            if (_selectedItem != null)
            {
                _selectedItem.Control.BorderColor = Color.Black;
            }

            if (selectedItem != null)
            {
                selectedItem.Control.BorderColor = Color.Red;
            }

            _selectedItem = selectedItem;

            if (_selectedItem != null && ItemSelectedChanged != null)
            {
                ItemSelectedChanged(this, EventArgs.Empty);
            }
        }

        private void OnItemMouseDoubleClick(MouseEventArgs e, ImageButtonListViewItem item)
        {
            if (ItemMouseDoubleClick != null)
            {
                ItemMouseDoubleClick(this, new ItemMouseEventArgs(item, e.Button, e.Clicks, e.X, e.Y, e.Delta));
            }
        }

        private void OnItemMouseDown(MouseEventArgs e, ImageButtonListViewItem item)
        {
            if (ItemMouseDown != null)
            {
                ItemMouseDown(this, new ItemMouseEventArgs(item, e.Button, e.Clicks, e.X, e.Y, e.Delta));
            }
        }

        private void OnItemMouseUp(MouseEventArgs e, ImageButtonListViewItem item)
        {
            if (ItemMouseUp != null)
            {
                ItemMouseUp(this, new ItemMouseEventArgs(item, e.Button, e.Clicks, e.X, e.Y, e.Delta));
            }
        }

        public class ButtonItemCollection : ListEx<ImageButtonListViewItem>
        {
            public void Add(string text, string key, object tag, Image backImg)
            {
                if (key.IsNullOrEmpty())
                {
                    key = text;
                }

                base.Add(new ImageButtonListViewItem(text, key, tag, backImg));

            }
        }

        public class ItemSelectedChangingEventArgs : EventArgs
        {
            public ItemSelectedChangingEventArgs(ImageButtonListViewItem selectingItem)
            {
                SelectingItem = selectingItem;

                Cancel = false;
            }

            public ImageButtonListViewItem SelectingItem { get; set; }

            public bool Cancel { set; get; }
        }

        public class ItemMouseEventArgs : MouseEventArgs
        {
            private ImageButtonListViewItem _item = null;

            public ItemMouseEventArgs(ImageButtonListViewItem item, MouseButtons button, int clicks, int x, int y, int delta)
                : base(button, clicks, x, y, delta)
            {
                _item = item;
            }

            public ImageButtonListViewItem ClickItem
            {
                get { return _item; }
            }
        }





    }



    public class ImageButtonListViewItem
    {
        public ImageButtonListViewItem(string text, string key = "", object tag = null, Image backImage = null)
        {
            Text = text;
            Key = key.IsNullOrEmpty() ? text : key;
            Tag = tag;
            BackImage = backImage;
        }

        public string Text;
        public string Key;
        public object Tag;
        public Image BackImage;

        internal LabelEx Control;

    }


}
